package cn.dglydrpy.study.mybatis.plugin;

import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;


/**
 * @Description:  自定义Mybatis插件
 * @author:LY_飘涯
 * @date:2019年6月7日 下午5:21:40 
 * @version:1.0
 */
@Intercepts(
		@Signature(type=StatementHandler.class,
				   method="prepare",
				   args= {Connection.class,Integer.class}))   //2.设置拦截方法的签名  //3.在mybatis的xml里配置plugin节点 ,设置类和properties属性
public class MyPlugin implements Interceptor{  //1.实现Interceptor 重写3个方法
	
	private Properties properties = null;
	private Integer limitLine = null;

	/**
	 * 拦截方法：只要被拦截的目标对象的目标方法被执行时，每次都会执行intercept方法
	 * 可以覆盖拦截对象原有的方法,可以通过invocation反射调用对象原来的方法
	 */
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		System.out.println("----- before -----");
		StatementHandler statementHandler = (StatementHandler)invocation.getTarget(); //得到的是代理对象
		//MetaObject可以帮助我们读取或修改重要对象里的一些属性
		MetaObject stateMetaObject = SystemMetaObject.forObject(statementHandler);//forObject帮助包装对象,现在被Mytatis提供的SystemMetaObject中的forObject替代
		while(stateMetaObject.hasGetter("h")) {
			Object object = stateMetaObject.getValue("h"); //getValue获取对象属性值
			stateMetaObject = SystemMetaObject.forObject(object);
		}
		while(stateMetaObject.hasGetter("target")) {
			Object obj = stateMetaObject.getValue("target");
			stateMetaObject = SystemMetaObject.forObject(obj);
		}
		String sql = (String) stateMetaObject.getValue("delegate.boundSql.sql");
		System.out.println("修改前的sql:"+sql);
		if (sql.contains("select") || sql.contains("SELECT")) {
			sql = sql + " limit "+ this.limitLine;
			stateMetaObject.setValue("delegate.boundSql.sql", sql); //setValue修改对象属性值
		}
		System.out.println("修改后的sql:"+sql);
		return invocation.proceed(); //原方法执行
	}

	/**
	 * 主要为了把当前的拦截器生成代理存到拦截器链中
	 * 为拦截对象target生成代理对象,Mybatis提供了Plugin.wrap()静态方法可帮助我们生成代理对象
	 */
	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	/**
	 * 获取配置文件中在的Plugin元素里配置的参数
	 */
	@Override
	public void setProperties(Properties properties) {
		this.properties = properties;
		System.out.println("数据库类型:"+properties.getProperty("dbType"));
		this.limitLine = Integer.parseInt((String) properties.getProperty("limitLine","50")); //50为默认值
	}

}
